/*
 * Copyright 2010-2012 Susanta Tewari. <freecode4susant@users.sourceforge.net>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package coalescent.cef.pui.pob;

import cef.pui.pob.Builder;
import cef.pui.pob.BuilderException;
import coalescent.recursion.ExactRecursionListeners;
import coalescent.recursion.RecursionListener;
import commons.util.ValidationUtil;

import javax.xml.bind.PropertyException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import static coalescent.recursion.RecursionComputers.*;

/**
 * @author Susanta Tewari
 */
abstract class RecursionComputationsBuilder<L extends RecursionListener> extends Builder<List<L>> {

    private static final String PROP_EXACT_PROB        = "exactProb";
    private static final String PROP_CONFIG_COUNTER    = "configCounter";
    private static final String PROP_GENEALOGY_COUNTER = "genealogyCounter";
    private static final String PROP_CONFIG_BUILDER    = "configBuilder";
    private static final String PROP_GENEALOGY_BUILDER = "genealogyBuilder";
    private static final String PROP_FC_CHECKER        = "fcChecker";

    RecursionComputationsBuilder(final String propertyKeyPrefix, final Properties props)
            throws BuilderException {

        super(propertyKeyPrefix, props);

        addPropertyKey(PROP_EXACT_PROB);
        addPropertyKey(PROP_CONFIG_COUNTER);
        addPropertyKey(PROP_GENEALOGY_COUNTER);
        addPropertyKey(PROP_CONFIG_BUILDER);
        addPropertyKey(PROP_GENEALOGY_BUILDER);
        addPropertyKey(PROP_FC_CHECKER);
    }

    /**
     * @param prop
     * @return
     * @throws BuilderException
     */
    protected boolean loadProp(final String prop) throws BuilderException {

        final String exactProbKey = getFullPropertyKey(prop);
        final String propVal      = getProperty(exactProbKey);

        if (propVal == null) {
            return false;
        }

        try {
            ValidationUtil.validateProperty(exactProbKey, getProperty(exactProbKey));
        } catch (PropertyException ex) {
            throw new BuilderException("Invalid property for RecursionComputationsBuilder", ex);
        }

        final boolean result;

        try {
            result = Boolean.parseBoolean(getProperty(exactProbKey));
        } catch (NumberFormatException ex) {
            throw new BuilderException("", ex);
        }

        return result;
    }

    /**
     * @version version
     * @since 1.4.0
     * @history Created on 03/24/2013
     * @author Susanta Tewari
     */
    public static class DEFAULT extends RecursionComputationsBuilder<RecursionListener> {

        DEFAULT(final String propertyKeyPrefix, final Properties props) throws BuilderException {
            super(propertyKeyPrefix, props);
        }

        @Override
        protected List<RecursionListener> buildFromProps() {

            final List<RecursionListener> computations = new ArrayList<>();

            if (loadProp(PROP_EXACT_PROB)) computations.add(getExactProbComputer());
            if (loadProp(PROP_CONFIG_COUNTER)) computations.add(getConfigCounter());
            if (loadProp(PROP_GENEALOGY_COUNTER)) computations.add(getGenealogyCounter());
            if (loadProp(PROP_CONFIG_BUILDER)) computations.add(getConfigBuilder());
            if (loadProp(PROP_GENEALOGY_BUILDER)) computations.add(getGenealogyBuilder());
            if (loadProp(PROP_FC_CHECKER)) computations.add(getFwdCountChecker());

            return computations;
        }

        @Override
        public String getBuilderString() {
            return "NotYetNecessary";
        }
    }

    /**
     * @version version
     * @since 1.4.0
     * @history Created on 04/03/2013
     * @author Susanta Tewari
     */
    public static class ME extends RecursionComputationsBuilder<ExactRecursionListeners.ME> {

        ME(final String propertyKeyPrefix, final Properties props) throws BuilderException {
            super(propertyKeyPrefix, props);
        }

        @Override
        protected List<ExactRecursionListeners.ME> buildFromProps() {

            final List<ExactRecursionListeners.ME> computations = new ArrayList<>();

            if (loadProp(PROP_EXACT_PROB)) computations.add(getExactProbComputer());

            return computations;
        }

        @Override
        public String getBuilderString() {
            return "NotYetNecessary";
        }
    }

    /**
     * @version version
     * @since 1.4.0
     * @history Created on 03/24/2013
     * @author Susanta Tewari
     */
    public static class MT extends RecursionComputationsBuilder<ExactRecursionListeners.MT> {

        MT(final String propertyKeyPrefix, final Properties props) throws BuilderException {
            super(propertyKeyPrefix, props);
        }

        @Override
        protected List<ExactRecursionListeners.MT> buildFromProps() {

            final List<ExactRecursionListeners.MT> computations = new ArrayList<>();

            if (loadProp(PROP_EXACT_PROB)) computations.add(getExactProbComputer());

            return computations;
        }

        @Override
        public String getBuilderString() {
            return "NotYetNecessary";
        }
    }

    /**
     * @version version
     * @since 1.4.0
     * @history Created on 03/24/2013
     * @author Susanta Tewari
     */
    public static class MT_ME extends RecursionComputationsBuilder<ExactRecursionListeners.MT_ME> {

        MT_ME(final String propertyKeyPrefix, final Properties props) throws BuilderException {
            super(propertyKeyPrefix, props);
        }

        @Override
        protected List<ExactRecursionListeners.MT_ME> buildFromProps() {

            final List<ExactRecursionListeners.MT_ME> computations = new ArrayList<>();

            if (loadProp(PROP_EXACT_PROB)) computations.add(getExactProbComputer());

            return computations;
        }

        @Override
        public String getBuilderString() {
            return "NotYetNecessary";
        }
    }
}
